/*
 * File - NotImplementedException.cpp
 *
 * This file is part of the Inuitive SDK
 *
 * Copyright (C) 2014-2020 Inuitive All Rights Reserved
 *
 */

/**
 * \cond INTERNAL
 */

#include "config.h"

#include <functional>
#include <string>
#include <sstream>
#include <string.h>

#include <execinfo.h>
#include <typeinfo>
#include <cxxabi.h>

/**
 * \endcond
 */

#include "NotImplementedException.h"

/**
 * \file NotImplementedException.cpp
 *
 * \brief NotImplementedException
 */

/**
 * \cond INTERNAL
 */

static const char rcsid[]="$Id: 3666c28f8d797e362e145b59356023166893fe86 $";

/**
 * \endcond
 */

namespace __INUROS__NAMESPACE__
{
    NotImplementedException::NotImplementedException(char const* str) throw()
        : std::logic_error(str)
    {
        void *addrlist[MAX_STACK_FRAMES+1];
        addrlen = backtrace(addrlist, MAX_STACK_FRAMES);
        symbolList = backtrace_symbols(addrlist, addrlen);
    }

    const char * NotImplementedException::what() const throw()
    {
        std::stringstream os;
        os << "Function " << std::logic_error::what() << " not yet implemented." << std::endl;

        // allocate string which will be filled with the demangled function name
        size_t funcnamesize = 256;
        char* funcname = (char*)malloc(funcnamesize);

        for (int i = 1; i < addrlen; i++)
        {
            char *beginName = nullptr;
            char *beginOffset = nullptr;
            char *endOffset = nullptr;

            // find parentheses and +address offset surrounding the mangled name:
            // ./module(function+0x15c) [0x8048a6d]

            for (char *p = symbolList[i]; *p; ++p)
            {
                    if (*p == '(')
                {
                    beginName = p;
                }
                    else if (*p == '+')
                {
                    beginOffset = p;
                }
                    else if (*p == ')' && beginOffset)
                {
                    endOffset = p;
                    break;
                }
            }

            if (true
                && beginName
                && beginOffset
                && endOffset
                && beginName < beginOffset
            )
            {
                *beginName++ = '\0';
                *beginOffset++ = '\0';
                *endOffset = '\0';

                // mangled name is now in [beginName, beginOffset) and caller
                // offset in [beginOffset, endOffset). now apply
                // __cxa_demangle():

                int status;
                char* ret = abi::__cxa_demangle(beginName, funcname, &funcnamesize, &status);

                if (status == 0)
                {
                    funcname = ret; // use possibly realloc()-ed string
                    os << "  " << symbolList[i] << " : " << funcname << "+" << beginOffset << std::endl;
                }
            }
            else
            {
                // demangling failed. Output function name as a C function with
                // no arguments.

                os << "  " << symbolList[i] << " : " << beginName << "()+" << beginOffset << std::endl;
            }
        }

        return strdup(os.str().c_str());
    }
}
